package ltd.jdsoft.cute.common.extention;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.reflections.Reflections;
import org.reflections.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ltd.jdsoft.cute.common.reflect.ExtensionReflect;
import ltd.jdsoft.cute.common.store.SimpleDataStore;
import ltd.jdsoft.cute.common.util.CuteDefaultDefine;
import ltd.jdsoft.cute.common.util.PropertyUtil;

/**
 * 扩展节点加载器
 * 
 * @author zhengzhq
 *
 */
public class ExtensionLoader {

  private static Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
  // 扩展点扫描的包路径
  public static final String BASE_PACKAGE = "ltd.jdsoft";
  // 参数的正则表达式匹配
  private static final Pattern PARAM_PATTERN = Pattern.compile("\\((.+)\\)");

  /**
   * 判断当前要解析的类是否用@Cute注解了
   * 
   * @param type
   * @return
   */
  private static <T> boolean withExtensionAnnotation(Class<T> type) {
    return type.isAnnotationPresent(SPI.class);
  }

  /**
   * 获取实现某个接口的所有类
   * 
   * @param type
   * @return
   */
  private static <T> Set<Class<? extends T>> getClassesWithImplementInterface(Class<T> type) {
    Reflections reflections = new Reflections(BASE_PACKAGE);
    return reflections.getSubTypesOf(type);
  }

  public static <T> List<Class<? extends T>> getClassesWithSort(Class<T> type) {
    Set<Class<? extends T>> classSet = getClassesWithImplementInterface(type);
    List<Class<? extends T>> classList = new ArrayList<>(classSet);
    classList.sort(new ExtentionComparator());

    return classList;
  }

  public static <T> T getExtention(Class<T> type, Class<? extends T> implementClass) {
    List<T> extList = getExtensionList(type, implementClass);
    if (extList.isEmpty()) {
      return null;
    }

    return extList.get(0);
  }

  @SuppressWarnings("unchecked")
  public static <T> List<T> getExtensionList(Class<T> type, String[] extensionNames) {
    List<T> extList = getExtensionList(type);
    List<T> retExtList = new ArrayList<>();

    if (extList.isEmpty()) {
      return retExtList;
    }

    if (extensionNames == null || extensionNames.length == 0) {
      return extList;
    }

    for (String extensionName : extensionNames) {
      String paramValue = extractParamValue(extensionName);
      String realExtensionName = paramValue == null ? extensionName
          : extensionName.substring(0, extensionName.indexOf("("));
      for (T ext : extList) {
        if (!ext.getClass().getSimpleName().equals(realExtensionName)) {
          continue;
        }

        // 不带有参数，直接返回默认的扩展节点实例
        if (paramValue == null) {
          retExtList.add(ext);
          break;
        }

        // 查看是在带有值的扩展节点中存在了
        String key = ext.getClass().getName() + "." + extensionName;
        if (!SimpleDataStore.contains(SimpleDataStore.EXTENSION_LOADER_WITH_PARAM, key)) {
          T newInstance = (T) newInstance(ext.getClass());
          ExtensionReflect.setValue(newInstance, paramValue);
          SimpleDataStore.put(SimpleDataStore.EXTENSION_LOADER_WITH_PARAM, key, newInstance);
        }

        retExtList.add((T) SimpleDataStore.get(SimpleDataStore.EXTENSION_LOADER_WITH_PARAM, key));
        break;
      }
    }

    return retExtList;
  }

  @SafeVarargs
  @SuppressWarnings("unchecked")
  public static <T> List<T> getExtensionList(Class<T> type, Class<? extends T>... classes) {
    if (type == null) {
      throw new IllegalStateException("Extention type should not be null!");
    }
    if (!type.isInterface()) {
      throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
    }
    if (!withExtensionAnnotation(type)) {
      throw new IllegalArgumentException("Extension type(" + type
          + ") is not extention, because without @" + SPI.class.getSimpleName() + " annotation!");
    }

    // 以完整类ltd.jdsoft.xxx.XXX作为key
    if (!SimpleDataStore.contains(SimpleDataStore.EXTENTION_LOADER, type.getName())) {
      initExtention(type);
    }

    List<T> instanceList =
        (List<T>) SimpleDataStore.get(SimpleDataStore.EXTENTION_LOADER, type.getName());
    // 如果没有指定的实现节点，默认返回全部
    if (instanceList.size() == 0 || classes.length == 0) {
      return instanceList;
    }

    List<T> retInstanceList = new ArrayList<>();
    for (Class<? extends T> classz : classes) {
      for (T instance : instanceList) {
        if (instance.getClass() == classz) {
          retInstanceList.add(instance);
        }
      }
    }

    return retInstanceList;
  }

  private static <T> void initExtention(Class<T> type) {
    synchronized (type) {
      // 再次确认是否初始过了，避免并发情况下初始化
      if (SimpleDataStore.contains(SimpleDataStore.EXTENTION_LOADER, type.getName())) {
        logger.warn("Extention [" + type.getName() + "] has already instantiated");
        return;
      }
      long startTime = System.currentTimeMillis();
      logger.info("start init extention[" + type.getName() + "]");

      Set<Class<? extends T>> classes = getClassesWithImplementInterface(type);
      if (classes.size() == 0) {// 没有符合条件的扩展节点实现
        SimpleDataStore.put(SimpleDataStore.EXTENTION_LOADER, type.getName(), new ArrayList<>());
        logger.warn("Extention[" + type.getName() + "] does not have implemention classes!");
      }

      // 对实现节点进行排序
      List<Class<? extends T>> classList = new ArrayList<>(classes);
      classList.sort(new ExtentionComparator());

      List<T> instanceList = new ArrayList<>();
      List<String> activeExtensionList = getActiveExtensionList(type);
      for (Class<? extends T> instanceType : classList) {
        // 如果有配置激活节点，以配置的为准
        if (activeExtensionList != null
            && !activeExtensionList.contains(instanceType.getSimpleName())) {
          continue;
        }
        instanceList.add(newInstance(instanceType));
      }
      SimpleDataStore.put(SimpleDataStore.EXTENTION_LOADER, type.getName(), instanceList);

      logger.info("finish init extention[" + type.getName() + "], cost "
          + (System.currentTimeMillis() - startTime) + " mill seconds");
    }
  }

  private static <T> T newInstance(Class<T> type) {
    try {
      return type.newInstance();
    } catch (Throwable e) {
      throw new IllegalStateException(
          "Extention[" + type.getName() + "] could not be instantiated!", e);
    }
  }

  private static <T> List<String> getActiveExtensionList(Class<T> type) {
    // 拼接key
    String key = CuteDefaultDefine.ACTIVE_EXTENSION_PREFIX + type.getSimpleName();
    String value = PropertyUtil.getDefaultConfig(key, String.class);

    if (Utils.isEmpty(value)) {
      return null;
    }

    return Arrays.asList(value.split(","));
  }

  private static String extractParamValue(String expression) {
    if (Utils.isEmpty(expression)) {
      return null;
    }

    Matcher matcher = PARAM_PATTERN.matcher(expression);
    while (matcher.find()) {
      return matcher.group(1);
    }

    return null;
  }
}
